//
//  open_protocol.h
//  open_protocol
//
//  Created by Eywen on 2021/2/3.
//

#ifndef _DG_DG_FRAME_H_
#define _DG_DG_FRAME_H_

#include <stdint.h>
#include <stdbool.h>
#include "common.h"

#define DG_FRAME_DEBUG true

#if DG_FRAME_DEBUG == true
#define debug_dg_frame_p(...)           \
    do                                  \
    {                                   \
        log_p("[dg frame debug] \t"); \
        log_p(__VA_ARGS__);           \
        log_p("\r\n");                \
    } while (0)
#define debug_dg_p(...)       \
    do                        \
    {                         \
        log_p(__VA_ARGS__); \
    } while (0)

#define _debug_dg_level(__LEVEL__, ...)     \
    do                                      \
    {                                       \
        log_p("[dgus %s: ]", #__LEVEL__); \
        log_p(__VA_ARGS__);               \
        log_p("\r\n");                    \
    } while (0)

#define debug_dg_faltal_p(...) _debug_dg_level(faltal, __VA_ARGS__)
#define debug_dg_error_p(...) _debug_dg_level(error, __VA_ARGS__)
#define debug_dg_warning_p(...) _debug_dg_level(warning, __VA_ARGS__)
#define debug_dg_info_p(...) _debug_dg_level(info, __VA_ARGS__)

#define debug_dg_hex_p(data, len) \
    debug_p_hex(data, len);       \
    log_p("\r\n")
#else
#define debug_dg_frame_p(...)
#define debug_dg_hex_p(data, len)
#define debug_dg_faltal_p(...)
#define debug_dg_error_p(...)    
#define debug_dg_warning_p(...)    
#define debug_dg_info_p(...)    
#endif

/* 帧中是否添加校验[DG_FRAME_CHECK_CRC16, DG_FRAME_CHECK_NONE] */
#define DG_FRAME_CHECK_NONE /* 无校验 */
//#define DG_FRAME_CHECK_CRC16 /* CRC16方式校验帧 */
//#define DG_FRAME_CHECK_SUM

/* 帧数据大小端定义 */
#define FFAME_ENDIAN DG_FRAME_LITTLE_ENDIAN

/* 最多能缓存的完整帧数量 */
#define DG_FRAME_BUF_LIST_MAX_LEN 16

/* 大端模式。高位在低字节，低位在高子节*/
#define DG_FRAME_BIG_ENDIAN 1
/* 小端标志 */
#define DG_FRAME_LITTLE_ENDIAN (!DG_FRAME_BIG_ENDIAN)

#define DG_FRAME_MAX_LEN 255

#define DG_FRAME_HEAD 0x5AA5

#define DG_FRAME_HEAD_OFFSET 0
/* 数据长度字段相对帧头的偏移 */
#define DG_FRAME_DATA_LEN_OFFSET (DG_FRAME_HEAD_OFFSET + 2)
/* 功能码字段相对帧头的偏移 */
#define DG_FRAME_FUN_CODE_OFFSET (DG_FRAME_DATA_LEN_OFFSET + 1)
/* 数据区域相对帧头的偏移 */
#define DG_FRAME_DATA_OFFSET (DG_FRAME_FUN_CODE_OFFSET + 1)

#if (defined DG_FRAME_CHECK_NONE)
#define DG_FRAME_MIN_LEN 3      /* 帧最小长度 */
#define DG_FRAME_DATA_LEN_MIN 1 /* 数据最小长度（包括指令、数据、校验字节） */
#else
/* 带校验 */
/* 校验开始的内容 */
#define DG_FRAME_CHECK_FIELD_BEGIN DG_FRAME_DATA_LEN_OFFSET
/* 最小校验长度，数据域为空情况下 */
#define DG_FRAME_CHECK_FIELD_MIN_LEN 1
#define DG_FRAME_MIN_CHEK_LEN 1 /* 校验最小长度 */

/* 校验码相对帧头的最小偏移 */
#define DG_FRAME_CHECK_CODE_MIN_OFFSET (DG_FRAME_DATA_OFFSET)
#define DG_FRAME_MIN_LEN 6      /* 帧最小长度 */
#define DG_FRAME_DATA_LEN_MIN 3 /* 数据最小长度（包括指令、数据、校验字节） */
/* 帧数据最大长度*/
#endif

/* 帧数据最大长度*/
#define DG_FRAME_MAX_DATA_LEN 249 //(DG_FRAME_MAX_LEN - DG_FRAME_MIN_LEN)


#define FRAME_BUS_BUFF_LEN (255U)


/* 报文框架,小端模式，低字节在低位 */
typedef struct _frame
{

    uint8_t buff[DG_FRAME_MAX_LEN];
    //uint8_t buff_send[DG_FRAME_MAX_LEN];

    uint16_t buff_write_index;
    uint16_t buff_read_index; /* 数据读取索引 */
} frame_t;

typedef struct _frame_list
{
    frame_t frame[DG_FRAME_BUF_LIST_MAX_LEN];
    uint8_t write_index;
    uint8_t read_index;
    uint8_t count;
} frame_list_t;

typedef enum _frame_status
{
    ok_integrity,    /* 具备完整的帧头和帧尾 */
    error_integrity, /* 没有完整的帧头或帧尾 */
    error_len,       /* 长度错误 */
    error_check,     /* 帧内容校验错误 */
    error_head,      /* 错误的头部 */
    error_tail,      /* 错误的尾部 */
    error_fun_code,  /* 不支持的功能码 */
} frame_status_t;

typedef bool (*handle_ptr)(frame_t *frame);

typedef struct _handle_t
{
    uint16_t fun_code;
    handle_ptr handle_fun;
} handle_t;

typedef enum _data_type
{
    data_type_int8,
    data_type_uint8,
    data_type_int16,
    data_type_uint16,
    data_type_int32,
    data_type_uint32,
    data_type_int64,
    data_type_uint64,
    data_type_float,
    data_type_double,
    data_type_bytes,
    data_type_string,
} frame_data_type_t;

bool handle_frame_buff(handle_t *frame_handle_list, uint16_t list_len);
frame_list_t *get_frame_list(void);
void frame_list_init(frame_list_t *frame_list);
frame_status_t deframe(uint8_t *frame_data, uint16_t frame_len);
uint8_t *frame_repy_create(frame_t *frame);
void frame_init(frame_t *frame, uint8_t fun_code);
void frame_repy_init(frame_t *repy_frame, frame_t *recv_frame);
uint16_t get_frame_write_idx_len(frame_t *frame);
uint8_t frame_pull_uint8(frame_t *frame);
uint16_t frame_pull_uint16(frame_t *frame);
uint32_t frame_pull_uint32(frame_t *frame);
uint64_t frame_pull_uint64(frame_t *frame);
float frame_pull_flaot(frame_t *frame);
uint16_t frame_pull_string(frame_t *frame, uint8_t *buff, uint16_t buff_len);
uint16_t frame_pull_bytes(frame_t *frame, uint8_t *buf, uint16_t buff_len);
uint8_t get_frame_fun_code(frame_t *frame);
uint8_t get_frame_data_len_field(frame_t *frame);
uint8_t get_frame_data_len(frame_t *frame);
uint8_t get_frame_len(frame_t *frame);
void frame_push_uint8(frame_t *frame, uint8_t var);
void frame_push_uint16(frame_t *frame, uint16_t var);
void frame_push_uint32(frame_t *frame, uint32_t var);
void frame_push_uint64(frame_t *frame, uint64_t var);
void frame_push_float(frame_t *frame, float var);
void frame_push_double(frame_t *frame, double var);
void frame_push_bytes(frame_t *frame, uint8_t *bytes, uint16_t len);
void frame_push_string(frame_t *frame, char *str);

void set_frame_fun_code(frame_t *frame, uint8_t fun_code);
void set_frame_data_len_field(frame_t *frame, uint8_t date_len);
void set_frame_head(frame_t *frame, uint16_t head);
void frame_set(frame_t *frame, uint8_t funcode, int data_num, ...);
void print_frame(frame_t *frame);

#endif /* open_protocol_h */
